extends Object
var classArray = []
var classDict = {}
var returnToken
var heads={}
var jscode=""
var actions={}

func createFilterMap():
	actions["math.abs"]="Math.abs(%s)"
	actions["math.max"]="Math.max(%s)"
	actions["math.min"]="Math.min(%s)"
	actions["math.floor"]="Math.floor(%s)"
	actions["math.ceil"]="Math.ceil(%s)"
	actions["math.acos"]="Math.acos(%s)"
	actions["math.asin"]="Math.asin(%s)"
	actions["math.atan"]="Math.atan(%s)"
	actions["math.atan2"]="Math.atan2(%s)"
	actions["math.cos"]="Math.cos(%s)"
	actions["math.sin"]="Math.sin(%s)"
	actions["math.tan"]="Math.tan(%s)"
	
	actions["type"]="typeof(%s)"
	actions["cc.p"]="cc.v2(%s)"
	actions["cc.DelayTime.create"]="cc.delayTime(%s)"
	actions["cc.Sequence.create"]="cc.sequence(%s)"
	actions["cc.Spawn.create"]="cc.spawn(%s)"
	actions["cc.CallFunc.create"]="cc.callFunc(%s)"
	actions["cc.RemoveSelf.create"]="cc.removeSelf(%s)"
	actions["cc.FadeIn.create"]="cc.fadeIn(%s)"
	actions["cc.FadeOut.create"]="cc.fadeOut(%s)"
	actions["cc.ScaleTo.create"]="cc.scaleTo(%s)"
	actions["cc.ScaleBy.create"]="cc.scaleBy(%s)"
	actions["cc.MoveTo.create"]="cc.moveTo(%s)"
	actions["cc.MoveBy.create"]="cc.moveBy(%s)"
	actions["cc.RotateBy.create"]="cc.rotateBy(%s)"
	actions["cc.RotateTo.create"]="cc.rotateTo(%s)"
	actions["cc.RepeatForever.create"]="cc.repeatForever(%s)"
	actions["cc.Show.create"]="cc.show(%s)"
	actions["cc.Hide.create"]="cc.hide(%s)"
	
	actions["cc.EaseIn.create"]="%s.easing(cc.easeIn())"
	actions["cc.EaseOut.create"]="%s.easing(cc.easeOut())"
	actions["cc.EaseCubicActionOut.create"]="%s.easing(cc.easeCubicActionOut())"
	actions["cc.EaseBackOut.create"]="%s.easing(cc.easeBackOut())"
	actions["cc.EaseBackInOut.create"]="%s.easing(cc.easeBackInOut())"
	actions["cc.EaseBackIn.create"]="%s.easing(cc.easeBackIn())"
	actions["cc.EaseElasticOut.create"]="%s.easing(cc.easeElasticOut())"
	actions["cc.EaseBounceOut.create"]="%s.easing(cc.easeBounceOut())"
	actions["cc.EaseExponentialOut.create"]="%s.easing(cc.easeExponentialOut())"
	actions["cc.EaseExponentialIn.create"]="%s.easing(cc.easeExponentialIn())"
	actions["cc.EaseSineIn.create"]="%s.easing(cc.easeSineIn())"


func get_file(path):
	path = path.replace("\n","")
	path = path.replace(".","/")
	return path.get_file()
		
func createClassCode(classInfo):
	var funcBody=""
	var property_str=""
	for property in classInfo.classPropertys:
		var right = luaOpcode(property.get("right",{})[0])
		if str(right)!="null":
			var left = property.get("left")[0].get("Index",{}).get("idx",{}).get("String",{}).get("s")		
			property_str="%s%s:%s,\n" % [property_str,left,right]
	funcBody="properties:{\n%s\n},\n" % [property_str]
	for method in classInfo.Methods:
		var name = method.get("name")
		var body =method.get("body")
		var args = method.get("args")				
		var supercall = "%s.super.%s" % [classInfo.className,name]
		var callName = name
		if name == "ctor":
			name = "__ctor__"
			callName = "constructor"
		body =body.replace(supercall,"%s.prototype.%s.call" % [classInfo.superName,callName])
		var func_str = "%s(%s){\n%s\n},\n" % [name,args,body]
		funcBody="%s%s" % [funcBody,func_str]
	
		
	var staticBody=""
	for fun_str in classInfo.get("StaticMethods"):
		staticBody = staticBody + fun_str
	var localBody=""
	if classInfo.localName and len(staticBody)>0:
		localBody="let %s = " % [classInfo.className]
	if classInfo.superName==null:
		return "%scc.Class({\n	name:\"%s\",\n %s\n});\n%s" % [localBody,classInfo.className,funcBody,staticBody]
	else:
		return "%scc.Class({\n	name:\"%s\",\nextends:%s,\n %s\n});\n%s" % [localBody,classInfo.className,classInfo.superName,funcBody,staticBody]
		
func findClassAndObj(ast):
	var bodys = ast.get("Chunk",{}).get("body",{}).get("Block",{}).get("body",[])
	for token in bodys:
		var targets = token.get("LocalAssign",{}).get("targets",[])
		var values = token.get("LocalAssign",{}).get("values",[])
		if values.size()>0:
			var Call = values[0].get("Call",{})
			var teampName = Call.get("func",{}).get("Name",{}).get("id","")
			if teampName=="class" or teampName=="classL":
				#找到类
				var ClassInfo={}
				ClassInfo.classPropertys=[]
				ClassInfo.StaticMethods=[]
				ClassInfo.Methods=[]
				var args = Call.get("args",[])
				var className = args[0].get("String",{}).get("s")
				var superName
				var localName
				if targets.size()>0:
					localName = targets[0].get("Name",{}).get("id")
				if args.size()>1:
					#有父类
					superName = luaOpcode(args[1],".")
				ClassInfo.className = className
				ClassInfo.superName = superName
				ClassInfo.localName = localName
				classArray.append(ClassInfo)
				classDict[ClassInfo.className] =ClassInfo
				classDict[ClassInfo.localName] =ClassInfo
	
	
		if token.get("Return"):
			returnToken = token.get("Return")
			token.erase("Return")

func _init(ast,filePath):
	if ast==null:		
		return
	createFilterMap()
	findClassAndObj(ast)
	
	heads["layer"]="UILayer"
	heads["node"]="UINode"
	var chunk = ast["Chunk"]
	var code = ""
	if chunk and chunk["body"]:
		var body = chunk["body"]
		code = luaBody(body)
		
	for classinfo in self.classArray:
		var class_code = createClassCode(classinfo)
		code = code + class_code
	
	if returnToken and self.classArray.size()==0:
		var values=returnToken.get("values",[])
		var return_value = concatOpcodeArray(values,",")
		code = code +"\nmodule.exports=" + return_value
					
	#print(code)
	jscode = code
	#print("result\n")
	
func concatOpcodeArray(array,split_char,isback=null):
	var ar_str=""
	for i in range(array.size()):
		var value = luaOpcode(array[i])
		if isback:
			value = luaOpcode(array[array.size()-1-i])
		if i==array.size()-1:
			ar_str="%s%s" % [ar_str,value]
		else:
			ar_str="%s%s%s" % [ar_str,value,split_char]	
	return ar_str

func isExpression(token):
	var express=["LAndOp","LOrOp","AddOp","SubOp","MultOp","FloatDivOp"]
	for i in range(express.size()):
		if token.get(express[i]):
			return true
	return false
	
func getLeftRightValue(token):
	var left = token.get("left")
	if left:
		var left_str=luaOpcode(token.get("left"))
		if isExpression(left):
			left="(%s)" % [left_str]
		else:
			left=left_str
	else:
		left=""
	var right = token.get("right")
	if right:
		var right_str = luaOpcode(right)
		if isExpression(right):
			right="(%s)" % [right_str]
		else:
			right=right_str
	else:
		right=""
	return [left,right]
	
func luaOpcode(token,ext=null):
	for key in token.keys():
		return call("lua"+key,token[key],ext)
		
func luaString(token,ext=null):
	var value = token.get("s","")
	return '"'+value +'\"'
	
func luaName(token,ext=null):
	if token.get("id")=="self":
		return "this"
	var classInfo = classDict.get(token.get("id"))
	if classInfo:
		return classInfo.className
	return token["id"]

#连接符..	
func luaConcat(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s + %s" % [left_right[0],left_right[1]]
func checkLuaArray(keys):
	var isArray=true
	for i in range(keys.size()):
		var obj = keys[i]
		if i!=int(obj.key)-1:
			isArray=false
	if keys.size()==0:
		isArray=false
	return isArray
		
func luaTable(token,ext=null):
	var fields = token.get("fields",[])
	var values=[]
	for field in fields:
		var Field = field.get("Field")
		#key 是不是在括号之间，在[]括号之间的为变量，js 变量不需要加双引号，需要加括号
		var between_brackets = Field.get("between_brackets",false)
		var newField = {}
		newField.between_brackets = between_brackets
		newField.key = luaOpcode(Field["key"])
		newField.value = luaOpcode(Field["value"])
		values.append(newField)
		
	var isarray = checkLuaArray(values)
	var code =""
	if isarray:
		var content=""
		for i in range(values.size()):
			var obj = values[i]
			content=content+String(obj.value)
			if i<values.size()-1:
				content=content+","
		code="[%s]" % [content]
	else:
		var content=""
		for i in range(values.size()):
			var obj = values[i]
			if obj.between_brackets:
				content="%s[%s]:%s" % [content,obj.key,obj.value]
			else:
				content="%s\"%s\":%s" % [content,obj.key,obj.value]
			if i<values.size()-1:
				content=content+","
		code="{%s}" % [content]
	return code
		
	
func luaNil(token,ext=null):
	return "null"
	
func luaNumber(token,ext=null):
	return token.get("n",0)
	
func luaTrue(token,ext=null):
	return "true"
	
func luaFalse(token,ext=null):
	return "false"
	
func luaIndex(token,ext=null):
	var property = luaOpcode(token["idx"],ext)
	var object = luaOpcode(token["value"],ext)
	if ext=="." or (typeof(property)==TYPE_STRING and property=="\"super\""):
		if typeof(property)==TYPE_STRING:
			property=property.replace("\"","")
		return "%s.%s" % [object,property]
	else:
		return "%s[%s]" % [object,property]
	
func luaULengthOp(token,ext=null):
	var operadnd =  luaOpcode(token["operand"])
	#数组长度表达式
	return operadnd+".length"
	
func luaVarargs(token,ext=null):
	return "...args"
	
func luaWhile(token,ext=null):
	 var body = luaBody(token.get("body"))
	 var expre = luaOpcode(token.get("test"))
	 return "while(%s){\n%s\n}" % [expre,body]
	
func luaBreak(token,ext=null):
	  return "break"
func luaDo(token,ext=null):
	#print(token)
	return ""
	
#分号;	
func luaSemiColon(token,ext=null):
	 return ""

# 加法	
func luaAddOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s+%s" % [left_right[0],left_right[1]]

# 减法	
func luaSubOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s-%s" % [left_right[0],left_right[1]]
	
#除法	
func luaFloatDivOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s/%s" % [left_right[0],left_right[1]]
#乘法	
func luaMultOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s*%s" % [left_right[0],left_right[1]]

#取模	
func luaModOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s%%%s" % [left_right[0],left_right[1]]
	
#非运算	
func luaULNotOp(token,ext=null):
	var operadnd =  luaOpcode(token["operand"])
	return "!" + operadnd

#等于
func luaREqOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s==%s" % [left_right[0],left_right[1]]

#不等于	
func luaRNotEqOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s!=%s" % [left_right[0],left_right[1]]

#与
func luaLAndOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s&&%s" % [left_right[0],left_right[1]]

#或	
func luaLOrOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s||%s" % [left_right[0],left_right[1]]

#大于	
func luaRGtOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s > %s" % [left_right[0],left_right[1]]

#大于等于
func luaRGtEqOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s >= %s" % [left_right[0],left_right[1]]

#小于	
func luaRLtOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s < %s" % [left_right[0],left_right[1]]

#小于等于
func luaRLtEqOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "%s <= %s" % [left_right[0],left_right[1]]
#x^2,平方
func luaExpoOp(token,ext=null):
	var left_right = getLeftRightValue(token)
	return "Math.pow(%s,%s)" % [left_right[0],left_right[1]]
	
func luaUMinusOp(token,ext=null):
	var operand = token.get("operand",{})
	return "-%s" % [luaOpcode(operand)]
	
func luaRepeat(token,ext=null):
	var test = luaOpcode(token.get("test"))
	var body = luaBody(token.get("body"))
	
	return "do {\n%s\n}\nwhile(%s)\n" % [body,test]

#操作块 test() 
func luaCall(token,ext=null):
	print(token)
	var func_name = luaOpcode(token["func"],".")
	var args=concatOpcodeArray(token.get("args",[]),",")
	var func_real_name = func_name.replace(".","/")
	func_real_name=func_real_name.get_file()
	
	if func_real_name=="class" or func_real_name=="classL":
		return ""
	if func_real_name=="require":
		args=args.replace("\"","")
		args=args.replace(".","/")
		args="\"%s\"" % [args.get_file()]	
	if actions.get(func_name):
		return actions[func_name] % [args]
	else:
		return "%s(%s)" % [func_name,args]
	
#local a=b
func luaLocalAssign(value,ext=null):
	var valuestr = concatOpcodeArray(value.get("values",[]),",")
	var targetsstr =  concatOpcodeArray(value["targets"],",")
	if classDict.get(targetsstr):
		return ""
	else:
		var targets = value["targets"]
		var values = value.get("values",[])
		var assign =""
		for i in range(targets.size()):
			var vkey = luaOpcode(targets[i])
			if i<=(values.size()-1):
				var vvalue=luaOpcode(values[i])
				assign = "%s%s = %s" % [assign,vkey,vvalue]
			else:
				assign = "%s%s" % [assign,vkey]
			if i<(targets.size()-1):
				assign = "%s," % [assign]
		return "let %s" % [assign]
	
func luaAssign(value,ext=null):	
	if value.get("targets") and value.get("targets")[0].get("Index") :
		var first = luaOpcode(value.get("targets")[0].get("Index").get("value"))
		var clasInfo = classDict.get(first)
		if clasInfo:
			#对象属性
			clasInfo.classPropertys.append({"left":value["targets"],"right":value.get("values",[])})
			return ""
	var targets = value["targets"]
	var values = value.get("values",[])
	var assign =""
	for i in range(targets.size()):
		var vkey = luaOpcode(targets[i])
		if i<=(values.size()-1):
			var vvalue=luaOpcode(values[i])
			var Index = targets[i].get("Index",{})
			var AddOp = Index.get("idx",{}).get("AddOp",{})
			if AddOp.get("left",{}).get("ULengthOp") && AddOp.get("right",{}).get("Number",{}).get("n",0)==1:
				#数组push
				var target=luaOpcode(Index.get("value",{}))
				assign = "%s%s.push(%s)" % [assign,target,vvalue]
			else:
				assign = "%s%s = %s" % [assign,vkey,vvalue]
		else:
			assign = "%s%s" % [assign,vkey]
		if i<(targets.size()-1):
			assign = "%s," % [assign]
	return assign
		
func luaBody(body,ext=null):
	var code = ""
	if body:
		if typeof(body) == TYPE_ARRAY:
			for value in body:
				for key in value.keys():
					var code_str = call("lua"+key,value[key])
					if len(code_str)>0:
						code = "%s%s\n" % [code,code_str]
		else:
			#body 里面有block ,block 里面还会有body
			if body.get("Block") and body.get("Block").get("body"):
				code = luaBody(body.get("Block").get("body"))
			else:
				print("error:\n",body)
	return code
	
func luaIf(value,ext=null):
	var test =  luaOpcode(value["test"])
	var body = luaBody(value.get("body"))
	var orelse = value.get("orelse")
	var elsestr=""
	if orelse:
		elsestr = "else"
		if orelse.get("ElseIf"):
			elsestr = elsestr+ " " + luaIf(orelse.get("ElseIf"),ext)
		else:
			elsestr="%s{\n%s\n}" % [elsestr,luaBody(orelse.get("Block",{}).get("body"))] 
			
	var result = "if(%s){\n%s\n}%s\n" % [test,body,elsestr]
	return result
	
#引用
func luaInvoke(value,ext=null):
	var args=  concatOpcodeArray(value.get("args",[]),",")
	var func_name = luaOpcode(value["func"])
	var source = value.get("source")
	var soure_str = luaOpcode(source,".")
	if len(soure_str)>0:
		soure_str=soure_str+"."
	var invokeName = "%s%s" % [soure_str,func_name]
	if actions.get(invokeName):
		return actions.get(invokeName) % [args]
	else:
		var invoke = "%s(%s)" % [invokeName,args]
		return invoke
	
	
func luaForin(value,ext=null):
	#转化为for eatch
	var body = luaBody(value.get("body"))
	var iter = ""
	if value["iter"][0].get("AnonymousFunction")!=null:
		iter=luaAnonymousFunction(value["iter"][0]["AnonymousFunction"])
	else:
		var call = value["iter"][0].get("Call")
		if call:
			iter = luaOpcode(call["args"][0])
		else:
			iter = ""
	var func_dict = value["iter"][0].get("Call")
	var iter_name="pairs"
	if func_dict:
		iter_name=luaOpcode(func_dict.get("func"))
	var array = iter
	var targets = value.get("targets")
	var targetIndex = luaOpcode(targets[0])
	var targetV=targetIndex
	if targets.size()==1:
		targetIndex = "i"
	else:
		targetV = luaOpcode(targets[1])		
	var for_parmter=concatOpcodeArray(targets,",",true)
	var code = ""
	if iter_name == "ipairs":
		code="for(let %s=0;%s<%s.length;%s++){\nlet %s = %s[%s]\n%s\n}"  % [targetIndex,targetIndex,array,targetIndex,targetV,array,targetIndex,body]
	else:
		if targets.size()==1:
			code="for (const %s in %s) {\n%s\n}" % [targetV,array,body]
		else:
			code="for (const %s in %s) {\nlet %s = %s[%s]\n%s\n}" % [targetIndex,array,targetV,array,targetIndex,body]
		
	return code
	
func subOonestr(strv):
	strv = "%s" % [strv]
	if typeof(strv) == TYPE_INT:
		strv=int(strv)-1
	else:
		if strv.is_valid_integer():
			strv=int(strv)-1
		else:
			strv="%s-1" % [strv]
	return strv

func luaFornum(value,ext=null):
	var target  = luaOpcode(value["target"])
	var begin =luaOpcode(value["start"])
	var stop = luaOpcode(value["stop"])
	var body = luaBody(value.get("body"))
	var step=null
	if value.get("step"):
		if typeof(value["step"]) == TYPE_DICTIONARY:
			step=luaOpcode(value["step"])
		else:
			step=value["step"]
			
	if int(step)==-1:
		#倒序
		stop = subOonestr(stop)
		begin = subOonestr(begin)
		return "for(let %s=%s;%s>=%s;%s--){\n%s\n}" % [target,begin,target,stop,target,body]
	else:
		begin = subOonestr(begin)
		return "for(let %s=%s;%s<%s;%s++){\n%s\n}" % [target,begin,target,stop,target,body]
		
	

func luaReturn(value,ext=null):
	var values=value.get("values",[])
	var return_value = concatOpcodeArray(values,",")
	return "return " + return_value
		

#对象方法	 lua中的:
func luaMethod(value,ext=null):
	var func_name = luaOpcode(value["name"])
	var soure_str = luaOpcode(value.get("source"))
	var body = luaBody(value.get("body"))
	var args = concatOpcodeArray(value.get("args",[]),",")
	var classInfo = classDict.get(soure_str)
	if classInfo:
		#外部类方法
		classInfo.Methods.append({"name":func_name,"obj":soure_str,"body":body,"args":args})
		return ""
	else:
		#方法内定义方法
		return  "%s.%s=function(%s){\n%s\n}" % [soure_str,func_name,args,body]
		
#静态方法
func luaFunction(value,ext=null):
	var names = value["name"]
	var func_fix=""
	var Index = names.get("Index")
	if Index:
		var property = luaOpcode(Index["idx"])
		var object = luaOpcode(Index["value"])
		property=property.replace("\"","")
		names="%s.%s" % [object,property]
	else:
		names = luaOpcode(value["name"],".")
	var args = concatOpcodeArray(value.get("args",[]),",")
	var body = luaBody(value.get("body"))
	var objs = names.rsplit(".", true, 1)
	var classInfo = classDict.get(objs[0])
	if classInfo:
		classInfo.StaticMethods.append("%s=function(%s){\n %s\n}\n" % [names,args,body])
		return ""
	else:
		var luafunc = "%s=function(%s){\n %s\n}\n" % [names,args,body]
		return luafunc
		
	
#匿名函数写法 local a =function() end	
func luaAnonymousFunction(value,ext=null):
	var func_body = luaBody(value.get("body"))
	var parmter = concatOpcodeArray(value.get("args",[]),",")
	
	return "function(%s){\n%s\n}" % [parmter,func_body]	
	
func luaLocalFunction(value,ext=null):
	var names = luaOpcode(value["name"])
	var args = concatOpcodeArray(value.get("args",[]),",")
	var body = luaBody(value.get("body"))
	var luafunc = "let %s=function(%s){\n %s\n}\n" % [names,args,body]
	
	return luafunc

